﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Emulator.Base.CPU;
using Emulator.GameBoy;
using Emulator.GameBoyConfig;

namespace Emulator.GameBoy.CPU
{
    public abstract class GameBoyInstruction : CPUInstructionBase
    {
        public abstract int InstructionTime { get; }
        public static GBInstructionResult DefaultInstructionResult = new GBInstructionResult();

#if DEBUG
        public abstract string InstructionName {get;}
#endif 

        public static GBInstructionResult PerformADCOperation(GameBoyCPU aCPU, int aValue)
        {
            int mResult = aCPU.ReadRegister8(GameBoyConfig.GBCPURegister.A) + aValue + (aCPU.CFlag ? 1 : 0);
            int mHalfResult = (aCPU.ReadRegister8(GameBoyConfig.GBCPURegister.A) & 0xf) + (aValue & 0xf) + (aCPU.CFlag ? 1 : 0);
            aCPU.ZFlag = (mResult == 0);
            aCPU.HFlag = (mHalfResult > 0xf);
            if (mResult > 0xFF)
            {
                aCPU.CFlag = true;
                mResult = (mResult & 255);//convert to byte
            }
            else
                aCPU.CFlag = false;

            aCPU.NFlag = false;
            aCPU.WriteRegister8(GameBoyConfig.GBCPURegister.A, mResult);
#if DEBUG
            DefaultInstructionResult.DebugInfo = string.Empty;
            DefaultInstructionResult.DebugInfo = Convert.ToString(aValue, 16);
#endif
            return DefaultInstructionResult;
        }

        public static GBInstructionResult PerformADD16Operation(GameBoyCPU aCPU, int aValue)
        {
            int mResult = aCPU.HLRegister + aValue;
            int mHalfResult = (aCPU.HLRegister & 0xFF) + (aValue & 0xFF);

            aCPU.ZFlag = (((UInt16)mResult) == 0);
            aCPU.HFlag = (mHalfResult > 0xff);
            if (mResult > 0xFFFF)
            {
                aCPU.CFlag = true;
                mResult = (mResult & 0xFFFF);//convert to double byte
            }
            else
                aCPU.CFlag = false;

            aCPU.NFlag = false;
            aCPU.WriteRegister8(GameBoyConfig.GBCPURegister.H, (mResult >> 8));
            aCPU.WriteRegister8(GameBoyConfig.GBCPURegister.L, (mResult & 0xFF));
#if DEBUG
            DefaultInstructionResult.DebugInfo = string.Empty;
            DefaultInstructionResult.DebugInfo = Convert.ToString(aValue, 16);
#endif
            return DefaultInstructionResult;
        }

        public static GBInstructionResult PerformADDOperation(GameBoyCPU aCPU, int aValue)
        {
            int mResult = aCPU.ReadRegister8(GameBoyConfig.GBCPURegister.A) + aValue;
            int mHalfResult = (aCPU.ReadRegister8(GameBoyConfig.GBCPURegister.A) & 0xf) + (aValue & 0xf);
            aCPU.ZFlag = (mResult == 0);
            aCPU.HFlag = (mHalfResult > 0xf);
            if (mResult > 0xFF)
            {
                aCPU.CFlag = true;
                mResult = (mResult & 255);//convert to byte
            }
            else
                aCPU.CFlag = false;

            aCPU.WriteRegister8(GameBoyConfig.GBCPURegister.A, mResult);
            aCPU.NFlag = false;
#if DEBUG
            DefaultInstructionResult.DebugInfo = string.Empty;
            DefaultInstructionResult.DebugInfo = Convert.ToString(aValue, 16);
#endif
            return DefaultInstructionResult;
        }

        public static GBInstructionResult PerformAND8Operation(GameBoyCPU aCPU, int aValue)
        {
            int mResult = aCPU.ReadRegister8(GameBoyConfig.GBCPURegister.A) & aValue;
            aCPU.ZFlag = (mResult == 0);
            aCPU.NFlag = false;
            aCPU.HFlag = true;
            aCPU.CFlag = false;

            aCPU.WriteRegister8(GameBoyConfig.GBCPURegister.A, mResult);
#if DEBUG
            DefaultInstructionResult.DebugInfo = string.Empty;
            DefaultInstructionResult.DebugInfo = Convert.ToString(aValue, 16);
#endif
            return DefaultInstructionResult;
        }

        public static GBInstructionResult PerformBITOperation(GameBoyCPU aCPU, int aPositionIndex, int aValue)
        {
            if ((aValue & (1 << aPositionIndex)) == (1 << aPositionIndex))
                aCPU.ZFlag = false;
            else
                aCPU.ZFlag = true;
            aCPU.NFlag = false;
            aCPU.HFlag = true;
#if DEBUG
            DefaultInstructionResult.DebugInfo = string.Empty;
            DefaultInstructionResult.DebugInfo = Convert.ToString(aPositionIndex, 16) + " " +
                Convert.ToString(aValue, 16);
#endif
            return DefaultInstructionResult;
        }

        public static GBInstructionResult PerformCALLOperation(GameBoyCPU aCPU, bool aCondition, UInt16 aAddress)
        {
            if (aCondition)
            {
                aCPU.PushStack((byte)(aCPU.ProgramCounter >> 8));
                aCPU.PushStack((byte)(aCPU.ProgramCounter & 0xFF));
                aCPU.ProgramCounter = aAddress;
            }
#if DEBUG
            DefaultInstructionResult.DebugInfo = string.Empty;
            DefaultInstructionResult.DebugInfo = Convert.ToString(aAddress, 16);
#endif
            return DefaultInstructionResult;
        }

        public static GBInstructionResult PerformCPOperation(GameBoyCPU aCPU, int aValue)
        {
            int mResult = aCPU.ReadRegister8(GameBoyConfig.GBCPURegister.A) - aValue;
            int mHalfResult = (aCPU.ReadRegister8(GameBoyConfig.GBCPURegister.A) & 15) - (aValue & 15);
            aCPU.ZFlag = (mResult == 0);
            aCPU.HFlag = (mHalfResult < 0);
            aCPU.CFlag = mResult < 0;
            aCPU.NFlag = true;
#if DEBUG
            DefaultInstructionResult.DebugInfo = string.Empty;
            DefaultInstructionResult.DebugInfo = Convert.ToString(aValue, 16);
#endif
            return DefaultInstructionResult;
        }

        public static GBInstructionResult PerformDEC16Operation(GameBoyCPU aCPU, int aHighRegIndex, int aLowRegIndex)
        {
            int mResult = aCPU.ReadRegister16(aHighRegIndex, aLowRegIndex);
            mResult--;
            aCPU.WriteRegister16(aHighRegIndex, aLowRegIndex, mResult);

#if DEBUG
            DefaultInstructionResult.DebugInfo = string.Empty;
            DefaultInstructionResult.DebugInfo = Convert.ToString((aHighRegIndex << 8) + aLowRegIndex, 16);
#endif
            return DefaultInstructionResult;
        }

        public static GBInstructionResult PerformDEC8Operation(GameBoyCPU aCPU, int aRegIndex)
        {
            int mResult = aCPU.ReadRegister8(aRegIndex);
            aCPU.HFlag = ((mResult & 0xF) == 0);
            mResult--;

            aCPU.WriteRegister8(aRegIndex, mResult);
            aCPU.ZFlag = mResult == 0;
            aCPU.NFlag = true;
#if DEBUG
            DefaultInstructionResult.DebugInfo = string.Empty;
            DefaultInstructionResult.DebugInfo = Convert.ToString(aRegIndex, 16);
#endif
            return DefaultInstructionResult;
        }

        public static GBInstructionResult PerformINC16Operation(GameBoyCPU aCPU, int aHighRegIndex, int aLowRegIndex)
        {
            int mResult = aCPU.ReadRegister16(aHighRegIndex, aLowRegIndex);
            mResult++;
            aCPU.WriteRegister16(aHighRegIndex, aLowRegIndex, (UInt16)mResult);
#if DEBUG
            DefaultInstructionResult.DebugInfo = string.Empty;
            DefaultInstructionResult.DebugInfo = Convert.ToString(aHighRegIndex, 16) +
                " " + Convert.ToString(aLowRegIndex, 16);
#endif
            return DefaultInstructionResult;
        }

        public static GBInstructionResult PerformINC8Operation(GameBoyCPU aCPU, int aRegIndex)
        {
            int mResult = aCPU.ReadRegister8(aRegIndex);

            aCPU.HFlag = (mResult & 0xF) == 0xF;
            mResult++;
            aCPU.WriteRegister8(aRegIndex, (byte)mResult);
            aCPU.ZFlag = ((byte)mResult) == 0;
            aCPU.NFlag = false;
#if DEBUG
            DefaultInstructionResult.DebugInfo = string.Empty;
            DefaultInstructionResult.DebugInfo = Convert.ToString(aRegIndex, 16);
#endif
            return DefaultInstructionResult;
        }

        public static GBInstructionResult PerformINTOperation(GameBoyCPU aCPU, int aInteruptVector)
        {
            aCPU.PushStack(aCPU.ProgramCounter);
            aCPU.ProgramCounter = (UInt16)aInteruptVector;

            return DefaultInstructionResult;
        }

        public static GBInstructionResult PerformJPOperation(GameBoyCPU aCPU, bool aFlag, UInt16 aAddress)
        {
            if (aFlag)
                aCPU.ProgramCounter = aAddress;
#if DEBUG
            DefaultInstructionResult.DebugInfo = string.Empty;
            DefaultInstructionResult.DebugInfo = Convert.ToString(aAddress, 16);
#endif
            return DefaultInstructionResult;
        }

        public static GBInstructionResult PerformJROperation(GameBoyCPU aCPU, bool aFlag, byte aOffset)
        {
            if (aFlag)
            {
               aCPU.ProgramCounter = (UInt16)(aCPU.ProgramCounter + (sbyte)aOffset);
            }
#if DEBUG
            DefaultInstructionResult.DebugInfo = string.Empty;
            DefaultInstructionResult.DebugInfo = Convert.ToString(aOffset, 16);
#endif
            return DefaultInstructionResult;
        }

        public static GBInstructionResult PerformLD2Memory16Operation(GameBoyCPU aCPU, GameBoy.Memory.GameBoyMemory aMemory, int aDstAddress, int aValue)
        {
            aMemory.Write8((UInt16)aDstAddress, (byte)(aValue & 0xFF));
            aMemory.Write8((UInt16)(aDstAddress + 1), (byte)(aValue >> 8));
#if DEBUG
            DefaultInstructionResult.DebugInfo = string.Empty;
            DefaultInstructionResult.DebugInfo = Convert.ToString(aDstAddress, 16) +
                " " + Convert.ToString(aValue, 16);
#endif
            return DefaultInstructionResult;
        }

        public static GBInstructionResult PerformLD2Memory8Operation(GameBoyCPU aCPU, GameBoy.Memory.GameBoyMemory aMemory, int aDstAddress, int aValue)
        {
            aMemory.Write8((UInt16)aDstAddress, (byte)aValue);
#if DEBUG
            DefaultInstructionResult.DebugInfo = string.Empty;
            DefaultInstructionResult.DebugInfo = Convert.ToString(aDstAddress, 16) +
                " " + Convert.ToString(aValue, 16);
#endif
            return DefaultInstructionResult;
        }

        public static GBInstructionResult PerformLD2Reg16Operation(GameBoyCPU aCPU, UInt16 aValue, int aHighRgIndex, int aLowRgIndex)
        {
            aCPU.WriteRegister8(aHighRgIndex, (byte)(aValue >> 8));
            aCPU.WriteRegister8(aLowRgIndex, (byte)(aValue & 0xFF));
#if DEBUG
            DefaultInstructionResult.DebugInfo = string.Empty;
            DefaultInstructionResult.DebugInfo = Convert.ToString(aHighRgIndex, 16) +
                Convert.ToString(aLowRgIndex, 16) + " " + Convert.ToString(aValue, 16);
#endif
            return DefaultInstructionResult;
        }

        public static GBInstructionResult PerformLD2Rg8Operation(GameBoyCPU aCPU, int aDstIndex, int aValue)
        {
            aCPU.WriteRegister8(aDstIndex, aValue);
#if DEBUG
            DefaultInstructionResult.DebugInfo = string.Empty;
            DefaultInstructionResult.DebugInfo = Convert.ToString(aDstIndex, 16) +
                " " + Convert.ToString(aValue, 16);
#endif
            return DefaultInstructionResult;
        }

        public static GBInstructionResult PerformOROperation(GameBoyCPU aCPU, int aValue)
        {
            int mResult = aCPU.ReadRegister8(GameBoyConfig.GBCPURegister.A) | aValue;
            aCPU.WriteRegister8(GBCPURegister.A, mResult);
            aCPU.ZFlag = (mResult == 0);
            aCPU.HFlag = false;
            aCPU.NFlag = false;
            aCPU.CFlag = false;
#if DEBUG
            DefaultInstructionResult.DebugInfo = string.Empty;
            DefaultInstructionResult.DebugInfo = Convert.ToString(aValue, 16);
#endif
            return DefaultInstructionResult;
        }

        public static GBInstructionResult PerformPOPOperation(GameBoyCPU aCPU, int aHighRegIndex, int aLowRegIndex)
        {
            aCPU.WriteRegister8(aLowRegIndex, aCPU.PopStack());
            aCPU.WriteRegister8(aHighRegIndex, aCPU.PopStack());
#if DEBUG
            DefaultInstructionResult.DebugInfo = string.Empty;
            DefaultInstructionResult.DebugInfo = Convert.ToString((aHighRegIndex << 8) + aLowRegIndex, 16);
#endif
            return DefaultInstructionResult;
        }

        public static GBInstructionResult PerformPUSHOperation(GameBoyCPU aCPU, int aHighRegIndex, int aLowRegIndex)
        {
            aCPU.PushStack((byte)aCPU.ReadRegister8(aHighRegIndex));
            aCPU.PushStack((byte)aCPU.ReadRegister8(aLowRegIndex));
#if DEBUG
            DefaultInstructionResult.DebugInfo = string.Empty;
            DefaultInstructionResult.DebugInfo = Convert.ToString((aHighRegIndex << 8) + aLowRegIndex, 16);
#endif
            return DefaultInstructionResult;
        }

        public static GBInstructionResult PerformRESMemOperation(GameBoy.Memory.GameBoyMemory aMemory, int aPosition, int aAddress)
        {
            aMemory.Write8((UInt16)aAddress,
                (byte)(aMemory.Read8((UInt16)aAddress) & (~GameBoyConfig.GBMemoryConfig.BitPositionMaskMap[aPosition])));

#if DEBUG
            DefaultInstructionResult.DebugInfo = string.Empty;
            DefaultInstructionResult.DebugInfo = Convert.ToString(aPosition, 16) + " " + Convert.ToString(aAddress, 16);
#endif
            return DefaultInstructionResult;
        }

        public static GBInstructionResult PerformRESRegOperation(GameBoyCPU aCPU, int aPosition, int aRegIndex)
        {
            aCPU.WriteRegister8(aRegIndex, aCPU.ReadRegister8(aRegIndex) 
                & (~GameBoyConfig.GBMemoryConfig.BitPositionMaskMap[aPosition]));

#if DEBUG
            DefaultInstructionResult.DebugInfo = string.Empty;
            DefaultInstructionResult.DebugInfo = Convert.ToString(aPosition, 16) + " " +
                Convert.ToString(aRegIndex, 16);
#endif
            return DefaultInstructionResult;
        }

        public static GBInstructionResult PerformRETOperation(GameBoyCPU aCPU, bool? aCondition)
        {
            if (aCondition == null || aCondition.Value == true)
            {
                byte mLowAddress = aCPU.PopStack();
                byte mHighAddress = aCPU.PopStack();
                aCPU.ProgramCounter = (UInt16)((mHighAddress << 8) + mLowAddress);
            }

#if DEBUG
            DefaultInstructionResult.DebugInfo = string.Empty;
            //DefaultInstructionResult.DebugInfo = Convert.ToString(aValue, 16);
#endif
            return DefaultInstructionResult;
        }

        public static GBInstructionResult PerformRLCOperation(GameBoyCPU aCPU, int aRegIndex)
        {
            int mRegAValue = aCPU.ReadRegister8(aRegIndex);
            bool mHeightestBit = (mRegAValue & 128) == 128;
            aCPU.WriteRegister8(aRegIndex, (byte)((mRegAValue << 1) + (mHeightestBit ? 1 : 0)));
            aCPU.CFlag = mHeightestBit;
            aCPU.ZFlag = aCPU.ReadRegister8(aRegIndex) == 0;
            aCPU.NFlag = false;
            aCPU.HFlag = false;
#if DEBUG
            DefaultInstructionResult.DebugInfo = string.Empty;
            DefaultInstructionResult.DebugInfo = Convert.ToString(aRegIndex, 16);
#endif
            return DefaultInstructionResult;
        }

        public static GBInstructionResult PerformRLOperation(GameBoyCPU aCPU, int aRegIndex)
        {
            bool mCurrentCFlag = aCPU.CFlag;
            int mRegResultValue = (aCPU.ReadRegister8(aRegIndex) << 1);
            aCPU.CFlag = mRegResultValue > 0xFF;
            aCPU.NFlag = false;
            aCPU.HFlag = false;

            aCPU.WriteRegister8(aRegIndex, ((byte)(mRegResultValue + (mCurrentCFlag ? 1 : 0))));

            aCPU.ZFlag = aCPU.ReadRegister8(aRegIndex) == 0;
#if DEBUG
            DefaultInstructionResult.DebugInfo = string.Empty;
            DefaultInstructionResult.DebugInfo = Convert.ToString(aRegIndex, 16);
#endif
            return DefaultInstructionResult;
        }

        public static GBInstructionResult PerformRRCOperation(GameBoyCPU aCPU, int aRegIndex)
        {
            int mRegAValue = aCPU.ReadRegister8(aRegIndex);
            bool mSmallestBit = (mRegAValue & 1) == 1;
            aCPU.WriteRegister8(aRegIndex, (byte)((mRegAValue >> 1) + (mSmallestBit ? 0x80 : 0)));
            aCPU.CFlag = mSmallestBit;
            aCPU.ZFlag = aCPU.ReadRegister8(aRegIndex) == 0;
            aCPU.NFlag = false;
            aCPU.HFlag = false;
#if DEBUG
            DefaultInstructionResult.DebugInfo = string.Empty;
            DefaultInstructionResult.DebugInfo = Convert.ToString(aRegIndex, 16);
#endif
            return DefaultInstructionResult;
        }

        public static GBInstructionResult PerformRROperation(GameBoyCPU aCPU, int aRegIndex)
        {
            bool mCurrentCFlag = aCPU.CFlag;
            int mRegResultValue = aCPU.ReadRegister8(aRegIndex);
            aCPU.CFlag = (mRegResultValue & 1) == 1;
            aCPU.NFlag = false;
            aCPU.HFlag = false;

            aCPU.WriteRegister8(aRegIndex, ((byte)((mRegResultValue >> 1) + (mCurrentCFlag ? 0x80 : 0))));

            aCPU.ZFlag = aCPU.ReadRegister8(aRegIndex) == 0;
#if DEBUG
            DefaultInstructionResult.DebugInfo = string.Empty;
            DefaultInstructionResult.DebugInfo = Convert.ToString(aRegIndex, 16);
#endif
            return DefaultInstructionResult;
        }

        public static GBInstructionResult PerformRSTOperation(GameBoyCPU aCPU, byte aValue)
        {
            //byte[] mProgramCounter = aCPU.GetProgramCountArray();
            aCPU.PushStack((byte)(aCPU.StackPointer >> 8));
            aCPU.PushStack((byte)aCPU.StackPointer);
            aCPU.ProgramCounter = (UInt16)aValue;
#if DEBUG
            DefaultInstructionResult.DebugInfo = string.Empty;
            DefaultInstructionResult.DebugInfo = Convert.ToString(aValue, 16);
#endif
            return DefaultInstructionResult;
        }

        public static GBInstructionResult PerformSBCOperation(GameBoyCPU aCPU, int aValue)
        {
            int mResult = aCPU.ReadRegister8(GameBoyConfig.GBCPURegister.A) - aValue - (aCPU.CFlag ? 1 : 0);
            int mHalfResult = (aCPU.ReadRegister8(GameBoyConfig.GBCPURegister.A) & 15) - (aValue & 15);
            aCPU.ZFlag = (mResult == 0);
            aCPU.HFlag = (mHalfResult < 0);
            if (mResult < 0)
                aCPU.CFlag = true;
            else
                aCPU.CFlag = false;

            aCPU.WriteRegister8(GameBoyConfig.GBCPURegister.A, (byte)mResult);
            aCPU.NFlag = true;
#if DEBUG
            DefaultInstructionResult.DebugInfo = string.Empty;
            DefaultInstructionResult.DebugInfo = Convert.ToString(aValue, 16);
#endif
            return DefaultInstructionResult;
        }

        public static GBInstructionResult PerformSETMemOperation(GameBoy.Memory.GameBoyMemory aMemory, int aPosition, UInt16 aAddress)
        {
            aMemory.Write8(aAddress,
                (byte)(aMemory.Read8(aAddress) | GameBoyConfig.GBMemoryConfig.BitPositionMaskMap[aPosition]));
#if DEBUG
            DefaultInstructionResult.DebugInfo = string.Empty;
            DefaultInstructionResult.DebugInfo = Convert.ToString(aPosition, 16) + " " + Convert.ToString(aAddress, 16);
#endif
            return DefaultInstructionResult;
        }

        public static GBInstructionResult PerformSETRegOperation(GameBoyCPU aCPU, int aPosition, int aRegIndex)
        {
            aCPU.WriteRegister8(aRegIndex,
                aCPU.ReadRegister8(aRegIndex) | GameBoyConfig.GBMemoryConfig.BitPositionMaskMap[aPosition]);
#if DEBUG
            DefaultInstructionResult.DebugInfo = string.Empty;
            DefaultInstructionResult.DebugInfo = Convert.ToString(aPosition, 16) + " " +
                Convert.ToString(aRegIndex, 16);
#endif
            return DefaultInstructionResult;
        }

        public static GBInstructionResult PerformSLAOperation(GameBoyCPU aCPU, int aRegIndex)
        {
            int mRegValue = aCPU.ReadRegister8(aRegIndex);
            bool mHeighestBit = (mRegValue & 0x80) == 0x80;
            aCPU.WriteRegister8(aRegIndex, (mRegValue << 1));
            aCPU.CFlag = mHeighestBit;
            aCPU.NFlag = false;
            aCPU.HFlag = false;
            aCPU.ZFlag = (mRegValue << 1) == 0;
#if DEBUG
            DefaultInstructionResult.DebugInfo = string.Empty;
            DefaultInstructionResult.DebugInfo = Convert.ToString(aRegIndex, 16);
#endif
            return DefaultInstructionResult;
        }

        public static GBInstructionResult PerformSRAOperation(GameBoyCPU aCPU, int aRegIndex)
        {
            int mRegValue = aCPU.ReadRegister8(aRegIndex);
            bool mHeighestBit = (mRegValue & 0x80) == 0x80;
            aCPU.WriteRegister8(aRegIndex, (mRegValue >> 1) | (mHeighestBit ? 0x80 : 0));
            aCPU.CFlag = false;
            aCPU.NFlag = false;
            aCPU.HFlag = false;
            aCPU.ZFlag = (mRegValue >> 1) == 0;
#if DEBUG
            DefaultInstructionResult.DebugInfo = string.Empty;
            DefaultInstructionResult.DebugInfo = Convert.ToString(aRegIndex, 16);
#endif
            return DefaultInstructionResult;
        }

        public static GBInstructionResult PerformSRLOperation(GameBoyCPU aCPU, int aRegIndex)
        {
            int mRegValue = aCPU.ReadRegister8(aRegIndex);
            bool mLowestBit = (mRegValue & 1) == 1;
            aCPU.WriteRegister8(aRegIndex, (mRegValue >> 1));
            aCPU.CFlag = mLowestBit;
            aCPU.NFlag = false;
            aCPU.HFlag = false;
            aCPU.ZFlag = (mRegValue >> 1) == 0;
#if DEBUG
            DefaultInstructionResult.DebugInfo = string.Empty;
            DefaultInstructionResult.DebugInfo = Convert.ToString(aRegIndex, 16);
#endif
            return DefaultInstructionResult;
        }

        public static GBInstructionResult PerformSUB8Operation(GameBoyCPU aCPU, int aValue)
        {
            int mResult = aCPU.ReadRegister8(GameBoyConfig.GBCPURegister.A) - aValue;
            int mHalfResult = (aCPU.ReadRegister8(GameBoyConfig.GBCPURegister.A) & 15) - (aValue & 15);
            aCPU.ZFlag = (mResult == 0);
            aCPU.HFlag = (mHalfResult < 0);
            if (mResult < 0)
                aCPU.CFlag = true;
            else
                aCPU.CFlag = false;

            aCPU.WriteRegister8(GameBoyConfig.GBCPURegister.A, (byte)mResult);
            aCPU.NFlag = true;
#if DEBUG
            DefaultInstructionResult.DebugInfo = string.Empty;
            DefaultInstructionResult.DebugInfo = Convert.ToString(aValue, 16);
#endif
            return DefaultInstructionResult;
        }

        public static GBInstructionResult PerformSWAPOperation(GameBoyCPU aCPU, int aRegIndex)
        {
            int mRegValue = aCPU.ReadRegister8(aRegIndex);
            int mResult = ((mRegValue & 0xF) << 4) + ((mRegValue & 0xF0) >> 4);
            aCPU.WriteRegister8(aRegIndex, mResult);
            aCPU.ZFlag = mResult == 0;
            aCPU.NFlag = false;
            aCPU.HFlag = false;
            aCPU.CFlag = false;
#if DEBUG
            DefaultInstructionResult.DebugInfo = string.Empty;
            DefaultInstructionResult.DebugInfo = Convert.ToString(aRegIndex, 16);
#endif
            return DefaultInstructionResult;
        }

        public static GBInstructionResult PerformXOROperation(GameBoyCPU aCPU, int aValue)
        {
            aCPU.WriteRegister8(GameBoyConfig.GBCPURegister.A, aCPU.ReadRegister8(GameBoyConfig.GBCPURegister.A) ^ aValue);
            aCPU.ZFlag = aCPU.ReadRegister8(GameBoyConfig.GBCPURegister.A) == 0;
            aCPU.NFlag = false;
            aCPU.HFlag = false;
            aCPU.CFlag = false;
#if DEBUG
            DefaultInstructionResult.DebugInfo = string.Empty;
            DefaultInstructionResult.DebugInfo = Convert.ToString(aValue, 16);
#endif
            return DefaultInstructionResult;
        }

        public abstract GBInstructionResult PerformOperation(GameBoyCPU aCPU, GameBoy.Memory.GameBoyMemory aMemory);
    }
}
